#include "serviceentity.h"

namespace infinity {

/*static*/ const ServiceKey ServiceEntity::Key = ServiceKey("Service::Entity");

//! @todo double buffer condemn entity:
//! condemn entity should setLifeState & push in a vector/queue of entities to condemn
//! during the update simulation, after update of living entities, we should collect
//! condemned entities in this vector and remove them from living entities

void ServiceEntity::condemnEntity(Entity* entity)
{
	dwAssert(entity != NULL, "Invalid parameter: entity is NULL");
	dwAssert(entity->getLifeState() == Entity::LifeState_Living, "Entity is still borning or has already been condemned");
	dwAssert(std::find(m_entities.begin(), m_entities.end(), entity) != m_entities.end(), "Entity has not been created");

	entity->setLifeState(Entity::LifeState_Condemned);
}

/*virtual*/ void ServiceEntity::renderDebug()
{
	super::renderDebug();

	// renderDebug borning entities
	EntitiesCollection::iterator borningEntitiesEnd = m_borningEntities.end();
	for (EntitiesCollection::iterator entityIt = m_borningEntities.begin(); entityIt != borningEntitiesEnd; ++entityIt)
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");

		entity->renderDebug();
	}

	// renderDebug living entities
	EntitiesCollection::const_iterator entitiesEnd = m_entities.end();
	for (EntitiesCollection::iterator entityIt = m_entities.begin(); entityIt != entitiesEnd; ++entityIt)
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");

		entity->renderDebug();
	}

	// renderDebug condemned entities
	EntitiesCollection::iterator condemnedEntitiesEnd = m_condemnedEntities.end();
	for (EntitiesCollection::iterator entityIt = m_condemnedEntities.begin(); entityIt != condemnedEntitiesEnd; ++entityIt)
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");

		entity->renderDebug();
	}
}

/*virtual*/ Service::State ServiceEntity::onInitializeSimulation()
{
	return super::onInitializeSimulation();
}

/*virtual*/ void ServiceEntity::onUpdateSimulation(dw::float32 deltaT)
{
	// Update borning entities
	EntitiesCollection::iterator borningEntitiesEnd = m_borningEntities.end();
	for (EntitiesCollection::iterator entityIt = m_borningEntities.begin(); entityIt != borningEntitiesEnd; )
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");
		dwAssert(entity->getLifeState() == Entity::LifeState_Borning, "Invalid entity");

		if (entity->needsSimulationInitialization())
		{
			entity->initializeSimulation();
		}

		dwAssert(entity->needsSimulationInitialization() || entity->isReadyForSimulation(), "An error occured during entity initialization, it'simulation will not be updated");

		if (!entity->needsSimulationInitialization())
		{
			entity->setLifeState(Entity::LifeState_Living);
			m_entities.push_back(entity);
			entityIt = m_borningEntities.erase(entityIt);

			borningEntitiesEnd = m_borningEntities.end();
		}
		else
		{
			++entityIt;
		}
	}

	// Update living entities
	EntitiesCollection::iterator entitiesEnd = m_entities.end();
	for (EntitiesCollection::iterator entityIt = m_entities.begin(); entityIt != entitiesEnd; )
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");
		dwAssert(entity->getLifeState() == Entity::LifeState_Living || entity->getLifeState() == Entity::LifeState_Condemned, "Invalid entity");

		if (entity->getLifeState() == Entity::LifeState_Condemned)
		{
			m_condemnedEntities.push_back(entity);
			entityIt = m_entities.erase(entityIt);
			entitiesEnd = m_entities.end();
		}
		else
		{
			if (entity->isReadyForSimulation())
			{
				entity->updateSimulation(deltaT);
			}
			else
			{
				condemnEntity(entity);
			}
			
			if (entity->getLifeState() == Entity::LifeState_Condemned)
			{
				m_condemnedEntities.push_back(entity);
				entityIt = m_entities.erase(entityIt);
				entitiesEnd = m_entities.end();
			}
			else
			{
				++entityIt;
			}
		}
	}

	// Update condemned entities
	EntitiesCollection::iterator condemnedEntitiesEnd = m_condemnedEntities.end();
	for (EntitiesCollection::iterator entityIt = m_condemnedEntities.begin(); entityIt != condemnedEntitiesEnd; )
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");
		dwAssert(entity->getLifeState() == Entity::LifeState_Condemned, "Invalid entity");

		if (entity->needsSimulationTermination())
		{
			entity->terminateSimulation();
		}

		if (!entity->needsSimulationTermination() && !entity->needsMediaTermination())
		{
			entityIt = m_condemnedEntities.erase(entityIt);

			delete entity;

			condemnedEntitiesEnd = m_condemnedEntities.end();
		}
		else
		{
			++entityIt;
		}
	}
}

/*virtual*/ Service::State ServiceEntity::onTerminateSimulation()
{
	dwAssert(m_borningEntities.empty(), "Some entities have are still not borned");
	dwAssert(m_entities.empty(), "Some entities have not been condemned");
	dwAssert(m_condemnedEntities.empty(), "Some entities have not been condemned");

	return super::onTerminateSimulation();
}

/*virtual*/ void ServiceEntity::onUpdateMedia(dw::float32 deltaT)
{
	// Update borning entities
	EntitiesCollection::const_iterator borningEntitiesEnd = m_borningEntities.end();
	for (EntitiesCollection::iterator entityIt = m_borningEntities.begin(); entityIt != borningEntitiesEnd; ++entityIt)
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");
		dwAssert(entity->getLifeState() == Entity::LifeState_Borning, "Invalid entity");

		if (entity->needsMediaInitialization())
		{
			entity->initializeMedia();
		}

		dwAssert(entity->needsMediaInitialization() || entity->isReadyForMedia(), "An error occured during entity initialization, it's media will not be updated");
	}

	// Update living entities
	EntitiesCollection::const_iterator entitiesEnd = m_entities.end();
	for (EntitiesCollection::iterator entityIt = m_entities.begin(); entityIt != entitiesEnd; ++entityIt)
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");
		dwAssert(entity->getLifeState() == Entity::LifeState_Living || entity->getLifeState() == Entity::LifeState_Condemned, "Invalid entity");

		if (entity->getLifeState() == Entity::LifeState_Living)
		{
			if (entity->needsMediaInitialization())
			{
				entity->initializeMedia();
			}

			dwAssert(entity->needsMediaInitialization() || entity->isReadyForMedia(), "An error occured during entity initialization, it's media will not be updated");

			if (entity->isReadyForSimulation())
			{
				entity->updateMedia(deltaT);
			}
		}
	}

	// Update condemned entities
	EntitiesCollection::const_iterator condemnedEntitiesEnd = m_condemnedEntities.end();
	for (EntitiesCollection::iterator entityIt = m_condemnedEntities.begin(); entityIt != condemnedEntitiesEnd; ++entityIt)
	{
		Entity* entity = *entityIt;

		dwAssert(entity != NULL, "Invalid entity");
		dwAssert(entity->getLifeState() == Entity::LifeState_Condemned, "Invalid entity");

		if (entity->needsMediaTermination())
		{
			entity->terminateMedia();
		}
	}
}

/*virtual*/ ServiceEntity::~ServiceEntity()
{
}

} // namespace infinity
